#    This file is part of OpenPolitik.
#
#    OpenPolitik is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    OpenPolitik is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with OpenPolitik.  If not, see <http://www.gnu.org/licenses/>.
import os
import re
import urllib
import random
import copy

import session

from google.appengine.api import users
from google.appengine.api import mail
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template

import op_models
import helpers

class GamePage(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]

		if liu == None:
			self.redirect(template_values["login_url"])
			return

		game = op_models.Game.get(self.request.get("game"))
		page = "game"
		if game == None:
			page = "_404"
		else:
			s = session.Session()

			if s.get("flash_msg") and s.get("flash_msg") != "":
				template_values["flash_msg"] = s["flash_msg"]
				s["flash_msg"] = ""

			template_values["game"] = game

			if liu in game.users:
				if self.request.get("page") == "" or not self.request.get("page").isdigit():
					page_num = 1
				else:
					page_num = int(self.request.get("page"))
				template_values["messages"] = op_models.Message.get_messages(liu, game, page_num)
				template_values["messageable"] = True

			if game.state == 0:
				if liu in game.users:
					template_values["join_text"] = "Leave this game"
				else:
					template_values["join_text"] = "Join this game"
			else:
				if liu in game.users:
					uig = op_models.UserInGame.gql("WHERE user = :1 AND game = :2", liu, game).fetch(1)
					template_values["uig"] = uig[0]

					orders = op_models.Order.gql("WHERE user = :1 AND game = :2", liu, game).fetch(1)
					if orders:
						template_values["orders"] = orders[0].orders

					if liu == game.admin:
						template_values["phases"] = op_models.PHASES[1:]
					template_values["current_phase"] = op_models.PHASES[game.state]
				else:
					page = "_404"

			template_values["uigs"] = op_models.UserInGame.all().filter("game = ", game).fetch(7)

			template_values["join_url"] = "/join?game=" + self.request.get("game")

		self.response.out.write(template.render(helpers.get_path(page), template_values))

class GamesPage(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]

		num_per_page = 10
		if self.request.get("page") == "" or not self.request.get("page").isdigit():
			page = 1
		else:
			page = int(self.request.get("page"))

		games = op_models.Game.all().filter("state = ", 0)

		if liu:
			template_values["games_in"] = op_models.UserInGame.get_games_for_user(liu)
		
		template_values["games"] = games.fetch(num_per_page, (page - 1) * num_per_page)

		self.response.out.write(template.render(helpers.get_path("games"), template_values))

class JoinGame(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]

		if liu == None:
			self.redirect(template_values["login_url"])
			return

		game = op_models.Game.get(self.request.get("game"))
		if game == None:
			self.response.out.write(template.render(helpers.get_path("_404"), template_values))
		else:
			s = session.Session()
			if liu in game.users:
				game.users.remove(liu)
				uig = op_models.UserInGame.all().filter("game = ", game.key()).filter("user = ", liu).fetch(1)
				
				if uig != []:
					uig[0].delete()

				if game.users == [] or game.admin == liu:
					game.delete()
					s["message"] = "Game ended."
					self.redirect("/message")
					return
				else:
					game.put()
			else:
				uigs = op_models.UserInGame.all().filter("user = ", liu).fetch(10)

				if len(uigs) == 10:
					s["message"] = "You can join a maximum of 10 games."
					self.redirect("/message")
					return
				else:
					game.users.append(liu)
					game.put()
					uig = op_models.UserInGame(user=liu, game=game)
					uig.put()

			self.redirect("/game?game=" + str(game.key()))

class StartGame(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]

		game = op_models.Game.get(self.request.get("game"))

		if game == None or game.admin != liu:
			self.response.out.write(template.render(helpers.get_path("_404"), template_values))
			return

		nations = copy.deepcopy(op_models.NATIONS)
		nations = nations[:-1]
		random.shuffle(nations)
		uigs = op_models.UserInGame.all().filter("game = ", game).fetch(7)

		i = 0
		for u in uigs:
			u.nation = nations[i]
			u.put()
			i += 1

			#send emails

			prefs = op_models.UserOptions.get_prefs(u.user)
			if prefs.prefs & op_models.UserOptions.SEND_EMAIL_ON_GAME_START != 0:
				mail.send_mail(sender=game.admin.email(),
				               to=prefs.email,
							   subject="The game '%s' has started." % game.name,
							   body="""
Hello %s,

The game titled "%s" has started on OpenPolitik.

Click here to see it: %s
""" % (u.user.nickname(), game.name, "http://openpolitik.appspot.com/game?game=" + str(game.key())))

		game.state = 1
		game.date = "Spring 1901"
		game.put()
		self.redirect("/game?game=" + self.request.get("game"))

class CreateGame(webapp.RequestHandler):
	errors = []

	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)

		if not template_values["liu"]:
			self.redirect(template_values["login_url"])
		else:
			template_values["errors"] = self.errors

			self.response.out.write(template.render(helpers.get_path("create_game"), template_values))

	def post(self):
		self.errors = []
		user = users.get_current_user()
		if not user:
			self.redirect(users.create_login_url(self.request.uri))
		else:
			name = self.request.get("name")

			if re.compile('/^\s*$/').match(name):
				self.errors.append("You must have a name for your game!")

			game = op_models.Game.all().filter("name = ", name).fetch(1)
			if game != []:
				self.errors.append("There is already a game with that name.")

			if len(self.errors) > 0:
				self.get()
			else:
				game = op_models.Game(name=name, admin=user)
				game.users = [user]
				game.put()
				uig = op_models.UserInGame(user=user, game=game)
				uig.put()

				#load in units
				f = open("defaults.dat", "r")
				result, errors = helpers.process_pieces(f.read())
				f.close()
				for r in result:
					p = op_models.Piece(game=game, x=r["x"], y=r["y"], loc=r["loc"],
						type=r["type"], colour=r["owner"])
					p.put()

				self.redirect("/game?game=" + str(game.key()))

class AllOrders(webapp.RequestHandler):
	def get(self):
		# AJAX call
		liu = users.get_current_user()
		game = op_models.Game.get(self.request.get("game"))

		if liu == None or game == None or liu != game.admin:
			return

		orders = op_models.Order.all().filter("game = ", game).fetch(7)

		if len(orders) == 0:
			self.response.out.write("No orders yet...")
			return

		output = ""

		for o in orders:
			uig = op_models.UserInGame.gql("WHERE user = :1 AND game = :2", o.user, game).fetch(1)
			uig = uig[0]
			output += "<b>%s (%s)</b> - <i>Sent at %s</i><br />%s<br /><br />" % (o.user.nickname(),
				uig.nation, o.created, o.orders)

		output += '<a href = "/generate_map?game=' + str(game.key()) + '">Generate Map</a><br /><br />'
		self.response.out.write(output)
				
class UpdateInfo(webapp.RequestHandler):
	def post(self):
		# AJAX call
		liu = users.get_current_user()
		game = op_models.Game.get(self.request.get("game"))

		if game == None or liu == None or liu != game.admin:
			return

		game.date = self.request.get("date")
		game.state = int(self.request.get("phase"))
		game.due_date = self.request.get("due_date")
		game.put()
		self.response.out.write("")

class ViewMap(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]

		game = op_models.Game.get(self.request.get("game"))

		if game == None or liu not in game.users:
			page = "_404"
		else:
			page = "view_map"

			locations = helpers.load_territories()

			pieces = op_models.Piece.all().filter("game = ", game).fetch(150)

			for p in pieces:
				#print p.loc
				str = ""
				if p.type == 1:
					str = "sc-"
				p.x = int(locations[p.loc][str +"x"])
				p.y = int(locations[p.loc][str +"y"])
			template_values["pieces"] = pieces

		self.response.out.write(template.render(helpers.get_path(page), template_values))


class GenerateMap(webapp.RequestHandler):
	def get(self):
		template_values = helpers.get_liu_stuff(self.request.uri)
		liu = template_values["liu"]
		game = op_models.Game.get(self.request.get("game"))

		if liu == None or game == None or liu != game.admin:
			page = "_404"
		else:
			page = "generate_map"
			orders = op_models.Order.gql("WHERE game = :1", game).fetch(7)

			orders_output = ""

			for o in orders:
				uig = op_models.UserInGame.gql("WHERE user = :1 AND game = :2", o.user, game).fetch(1)
				uig = uig[0]
				orders_output += "<b>%s (%s)</b> - <i>Sent at %s</i><br />%s<br /><br />" % (o.user.nickname(),
					uig.nation, o.created, o.orders)

			pieces = op_models.Piece.gql("WHERE game = :1", game).fetch(150)
			
			pieces_output = ""
			for p in pieces:
				type = op_models.PIECES[p.type]
				loc = p.loc
				owner = op_models.NATIONS_SHORT[p.colour]

				pieces_output += "%s %s %s\n" % (owner, type, loc)

			template_values["pieces"] = pieces_output
			template_values["orders"] = orders_output
			template_values["game"] = game

			s = session.Session()

			output = ""
			if s.get("errors"):
				errors = s["errors"]
				for e in errors:
					output += e + "<br />"
				s["errors"] = []

			if s.get("output"):
				output += s["output"]
				s["output"] = ""
			template_values["output"] = output

		self.response.out.write(template.render(helpers.get_path(page), template_values))

	def post(self):
		liu = users.get_current_user()
		game = op_models.Game.find_by_name(self.request.get("game"))

		pieces = self.request.get("pieces")

		result, errors = helpers.process_pieces(pieces)

		s = session.Session()
		
		if errors == []:
			# all good, insert everything
			pieces = op_models.Piece.all().filter("game = ", game).fetch(150)
			for p in pieces:
				p.delete()

			for r in result:
				p = op_models.Piece(game=game, x=r["x"], y=r["y"], loc=r["loc"],
					type=r["type"], colour=r["owner"])
				p.put()
			s["output"] = "Map saved."
		else:
			s["errors"] = errors
		self.get()

			
class Orders(webapp.RequestHandler):
	def post(self):
		# AJAX call
		liu = users.get_current_user()

		game = op_models.Game.get(self.request.get("game"))
		orders = self.request.get("orders")

		# error conditions: game/user doesn't exist, game isn't started, or user isn't in the game
		if game == None or liu == None or game.state == 0 or liu not in game.users:
			return

		orders = orders.replace("\n", "<br />")

		obj = op_models.Order.gql("WHERE user = :1 AND game = :2", liu, game).fetch(1)
		if obj:
			obj[0].delete()

		obj = op_models.Order(user=liu, game=game, orders=orders)
		obj.put()

		self.response.out.write(orders)

class Boot(webapp.RequestHandler):
	def post(self):
		# AJAX call
		liu = users.get_current_user()

		game = op_models.Game.get(self.request.get("game"))
		user = users.User(self.request.get("user"))

		if game == None or liu == None or user == None:
			return

		if game.admin != liu:
			return

		uig = op_models.UserInGame.gql("WHERE user = :1 AND game = :2", user, game).fetch(1)
		uig[0].delete()

		for type in ["sender", "to"]:
			while True:
				messages = op_models.Message.gql("WHERE %s = :1" % type, user).fetch(1000)

				if messages == []:
					break

				for m in messages:
					m.delete()

		game.users.remove(user)
		game.put()
		self.response.out.write("")

